package org.ala.tiktools.rpc.plugin.load_balance.pool;

import org.ala.tiktools.logs.LoggerFactory;
import org.ala.tiktools.rpc.plugin.node.INode;
import org.ala.tiktools.rpc.plugin.node.NodeKey;
import org.ala.tiktools.rpc.plugin.node.NodeStatusEnums;
import org.slf4j.Logger;

import java.util.Map;
import java.util.concurrent.*;
import java.util.function.BiConsumer;

/**
 * 节点池子
 * <p>  维护节点状态
 * <p>  别看现在是个弱鸡，第一版的pool是很强大的，基本上LoadBalance就是给他包一层壳
 * <p>  后来给INode做了状态监听，很多功能就拿走了
 *
 * @author ala
 * @date 2025-04-07 11:41
 */
public class NodePool {


    static Logger log = LoggerFactory.getLogger("rpc", "loadBalance");


    /**
     *  全部节点池
     */
    protected Map<NodeKey, INode> totalNodes = new ConcurrentHashMap<>();


    /**
     *  检测NodeKey是否存在
     */
    public boolean exists(NodeKey k) {return totalNodes.containsKey(k);}
    /**
     *  拿节点
     */
    public INode get(NodeKey k) {return totalNodes.get(k);}
    /**
     *  删除节点
     */
    public INode remove(NodeKey k) {return totalNodes.remove(k);}
    /**
     *  追加节点
     */
    public void appendAndActive(INode node) {
        totalNodes.put(node.key(), node);
        //  node挂载了状态回调，回调中会执行
        node.active();
//        AbstractLoadBalance.schedule.schedule(
//                ReActiveTask.build().node(node).activeSuccess(activeSuccess).activeError((t,e) -> {
//                    t.times++;
//                    long time = t.times * RpcConfigInfo.INSTANCE.getReActiveInterval();
//                    if (time > RpcConfigInfo.INSTANCE.getReActiveMaxInterval()) {
//                        time = RpcConfigInfo.INSTANCE.getReActiveMaxInterval();
//                    }
//                    log.warn(String.format("[NodePool append] NodeKey:%s 第 (%d) 次连接失败，(%s)ms 后尝试重连", node.key(), t.times, time), e);
//                    AbstractLoadBalance.schedule.schedule(t, time, TimeUnit.MILLISECONDS);
//                }),
//                0, TimeUnit.MILLISECONDS);
    }


    /**
     *  重连任务
     */
    public static class ReActiveTask implements Runnable {
        protected INode node;
        protected int times = 0;
        protected Runnable activeSuccess;
        protected NodeStatusEnums lastStatus;
        protected BiConsumer<ReActiveTask, Throwable> activeError;
        public static ReActiveTask build(){return new ReActiveTask();}
        @Override
        public void run() {
            //  尝试重连
            node.active().whenCompleteAsync((s, e) -> {
                //  如果已经成功激活
                if (NodeStatusEnums.ACTIVATE.equals(s)) {
                    if (activeSuccess != null) {activeSuccess.run();}
                }
                //  如果仍然是不可用状态，尝试重新激活
                else {
                    this.lastStatus = s;
                    if (activeError != null) {activeError.accept(this, e);}
                }
            });
        }
        public INode getNode() {
            return node;
        }
        public void setNode(INode node) {
            this.node = node;
        }
        public ReActiveTask node(INode node) {
            setNode(node);
            return this;
        }
        public int getTimes() {
            return times;
        }
        public void setTimes(int times) {
            this.times = times;
        }
        public ReActiveTask times(int times) {
            setTimes(times);
            return this;
        }
        public Runnable getActiveSuccess() {
            return activeSuccess;
        }
        public void setActiveSuccess(Runnable activeSuccess) {
            this.activeSuccess = activeSuccess;
        }
        public ReActiveTask activeSuccess(Runnable activeSuccess) {
            setActiveSuccess(activeSuccess);
            return this;
        }
        public BiConsumer<ReActiveTask, Throwable> getActiveError() {
            return activeError;
        }
        public void setActiveError(BiConsumer<ReActiveTask, Throwable> activeError) {
            this.activeError = activeError;
        }
        public ReActiveTask activeError(BiConsumer<ReActiveTask, Throwable> activeError) {
            setActiveError(activeError);
            return this;
        }
        public NodeStatusEnums getLastStatus() {
            return lastStatus;
        }
        public void setLastStatus(NodeStatusEnums lastStatus) {
            this.lastStatus = lastStatus;
        }
        public ReActiveTask lastStatus(NodeStatusEnums lastStatus) {
            setLastStatus(lastStatus);
            return this;
        }
    }
}
